package com.dsbj.common.msg;


import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Created with idea
 * Date: 2017/10/23 0023
 * Time: 16:14
 *
 * @author lvdong
 */

public class ResponseMessage<T> extends BaseResponse {

    protected T data;

    private Long timestamp;

    private boolean success;


    public T getData() {
        return data;
    }


    public void setSuccess(boolean success) {
        this.success = success;
    }

    public boolean isSuccess() {
        return success;
    }

    public Long getTimestamp() {
        return timestamp;
    }

    public static <T> ResponseMessage<T> error(String message) {
        return error(500, message);
    }

    public static <T> ResponseMessage<T> error(int status, String message) {
        ResponseMessage<T> msg = new ResponseMessage<>();
        msg.message = message;
        msg.status(status);
        msg.success = false;
        return msg.putTimeStamp();
    }

    public ResponseMessage<T> status(int status) {
        this.status = status;
        return this;
    }

    public ResponseMessage<T> data(T data) {
        this.data = data;
        return this;
    }

    private ResponseMessage<T> putTimeStamp() {
        this.timestamp = System.currentTimeMillis();
        return this;
    }

    public ResponseMessage<T> success(boolean success) {
        this.success = success;
        return this;
    }

    public static <T> ResponseMessage<T> ok(T result) {
        return  ok(result,null);
    }

    public static <T> ResponseMessage<T> ok() {
        return ok(null);
    }

    public static <T> ResponseMessage<T> ok(T result,String msg) {
        return new ResponseMessage<T>()
                .data(result)
                .message(msg)
                .success(true)
                .putTimeStamp()
                .status(200);
    }

    public static <T> ResponseMessage<T> okWithMsg(String msg){
        return ok(null,msg);
    }



    private ResponseMessage<T> message(String msg) {
        this.message = msg;
        return this;
    }

    private transient Map<Class<?>, Set<String>> includes;

    private transient Map<Class<?>, Set<String>> excludes;

    public Map<Class<?>, Set<String>> getExcludes() {
        return excludes;
    }

    public Map<Class<?>, Set<String>> getIncludes() {
        return includes;
    }

    private Set<String> getStringListFromMap(Map<Class<?>, Set<String>> map, Class type) {
        return map.computeIfAbsent(type, k -> new HashSet<>());
    }


    public ResponseMessage<T> include(Class<?> type, Collection<String> fields) {
        if (null == includes) {
            includes = Maps.newHashMap();
        }
        if (null == fields || fields.isEmpty()) {
            return this;
        }
        fields.forEach(field -> {
            if (field.contains(".")) {
                String[] tmp = field.split("[.]", 2);
                try {
                    Field field1 = type.getDeclaredField(tmp[0]);
                    if (field1 != null) {
                        include(field1.getType(), tmp[1]);
                    }
                } catch (Throwable e) {

                }
            } else {
                getStringListFromMap(includes, type).add(field);
            }
        });
        return this;
    }

    public ResponseMessage include(Collection<String> fields) {
        if (includes == null) {
            includes = new HashMap<>(16);
        }
        if (fields == null || fields.isEmpty()) {
            return this;
        }
        Class type;
        if (getData() != null) {
            type = getData().getClass();
        } else {
            return this;
        }
        include(type, fields);
        return this;
    }

    public ResponseMessage<T> exclude(Class type, Collection<String> fields) {
        if (excludes == null) {
            excludes = Maps.newHashMap();
        }
        if (fields == null || fields.isEmpty()) {
            return this;
        }
        fields.forEach(field -> {
            if (field.contains(".")) {
                String[] tmp = field.split("[.]", 2);
                try {
                    Field field1 = type.getDeclaredField(tmp[0]);
                    if (field1 != null) {
                        exclude(field1.getType(), tmp[1]);
                    }
                } catch (Throwable e) {
                }
            } else {
                getStringListFromMap(excludes, type).add(field);
            }
        });
        return this;
    }

    public ResponseMessage<T> exclude(Collection<String> fields) {
        if (excludes == null) {
            excludes = Maps.newHashMap();
        }
        if (fields == null || fields.isEmpty()) {
            return this;
        }
        Class type;
        if (getData() != null) {
            type = getData().getClass();
        } else {
            return this;
        }
        exclude(type, fields);
        return this;
    }

    public ResponseMessage<T> include(Class<?> type, String... fields) {
        return include(type, Arrays.asList(fields));
    }

    public ResponseMessage<T> exclude(Class<?> type, String... fields) {
        return exclude(type, Arrays.asList(fields));
    }


    @Override
    public String toString() {
        return JSON.toJSONStringWithDateFormat(this, "yyyy-MM-dd HH:mm:ss");
    }
}
